#!/usr/bin/env bash
# =====================================================================
#  TP LINUX INTERACTIF : « Jouer avec des yeux »
#
#  Lancement :   bash tp-linux.sh
#
#  - Le script ouvre UN shell de TP (un sous-terminal dans ton terminal).
#  - Le HOME de ce shell est un bac à sable, créé dans un dossier
#    temporaire (en mémoire, tmpfs) : modifier ~/.bashrc ici ne touche pas
#    le vrai .bashrc.
#  - À chaque commande tapée, le TP vérifie si l'étape en cours est réussie.
#  - Aucune progression n'est sauvegardée : quand le TP se ferme (exit,
#    Ctrl+D, fenêtre fermée, kill...), tout est nettoyé : bac à sable,
#    historique, processus xeyes lancés pendant le TP, et paquet x11-apps
#    s'il a été installé pendant le TP.
# =====================================================================

TP_TOTAL=8

# ---------------------------------------------------------------------
#  PARTIE 1 : lanceur (exécuté une seule fois, dans le terminal normal)
# ---------------------------------------------------------------------
if [[ -z "${TP_INSIDE:-}" ]]; then
  if [[ "${BASH_SOURCE[0]:-$0}" != "$0" ]]; then
    echo "Lance-moi avec :  bash tp-linux.sh   (et pas avec source)"
    return 1 2>/dev/null || exit 1
  fi
  SELF="$(readlink -f "$0")"

  # Dossier de travail jetable, privé, en mémoire si possible
  # (disparaît aussi tout seul au redémarrage).
  base="${XDG_RUNTIME_DIR:-}"
  [[ -d "$base" && -w "$base" ]] || base=/dev/shm
  [[ -d "$base" && -w "$base" ]] || base=/tmp
  TP_DIR="$(mktemp -d "$base/tp-linux.XXXXXX")" || { echo "Impossible de créer le dossier de TP."; exit 1; }
  chmod 700 "$TP_DIR"
  export TP_DIR
  mkdir -p "$TP_DIR/home"
  {
    echo '# Ceci est le .bashrc de ton bac à sable de TP.'
    echo '# Tu peux le modifier librement : ça ne touche pas ton vrai .bashrc.'
  } > "$TP_DIR/home/.bashrc"

  # État initial, pour ne défaire que ce que le TP a fait
  had_pkg=0
  command -v xeyes >/dev/null 2>&1 && had_pkg=1
  pre_xeyes=" $(pgrep -u "$UID" -x xeyes 2>/dev/null | tr '\n' ' ') "
  launcher_pid=$$
  child=""
  wd=""
  _tp_notty=""

  # Nettoyage complet. Idempotent : peut être appelé plusieurs fois.
  _tp_cleanup() {
    [[ -n "${_tp_cleaned:-}" ]] && return
    _tp_cleaned=1
    trap '' HUP INT TERM
    local p
    [[ -n "$wd" ]] && kill "$wd" 2>/dev/null
    # le shell de TP, s'il tourne encore
    if [[ -n "$child" ]] && kill -0 "$child" 2>/dev/null; then
      kill -HUP "$child" 2>/dev/null
      sleep 0.3
      kill -KILL "$child" 2>/dev/null
    fi
    # les xeyes apparus pendant le TP (pas ceux d'avant)
    for p in $(pgrep -u "$UID" -x xeyes 2>/dev/null); do
      [[ "$pre_xeyes" == *" $p "* ]] || kill "$p" 2>/dev/null
    done
    # le bac à sable (garde-fou : seulement un dossier créé par mktemp ci-dessus)
    case "$TP_DIR" in
      */tp-linux.??????) rm -rf -- "$TP_DIR" ;;
    esac
    # le paquet, seulement s'il n'y était pas avant le TP
    if (( ! had_pkg )) && dpkg -s x11-apps >/dev/null 2>&1; then
      if [[ -z "$_tp_notty" && -t 0 ]]; then
        echo "Désinstallation de x11-apps (installé pendant le TP)..."
        sudo apt-get remove -y x11-apps >/dev/null 2>&1 \
          || echo "Impossible de le désinstaller automatiquement. Fais : sudo apt remove x11-apps"
      else
        sudo -n apt-get remove -y x11-apps >/dev/null 2>&1
      fi
    fi
  }

  if [[ -z "${DISPLAY:-}" && -z "${WAYLAND_DISPLAY:-}" ]]; then
    echo "Attention : pas d'affichage graphique détecté (DISPLAY vide). xeyes ne pourra pas s'ouvrir."
  fi

  trap '_tp_cleanup' EXIT
  trap '_tp_notty=1; exit 129' HUP
  trap 'exit 143' TERM
  trap ':' INT

  # xeyes a besoin de l'autorisation X11, qui se trouve dans le vrai HOME
  if [[ -z "${XAUTHORITY:-}" && -f "$HOME/.Xauthority" ]]; then
    export XAUTHORITY="$HOME/.Xauthority"
  fi

  # Le shell de TP tourne en arrière-plan + wait, pour que les signaux
  # reçus par le lanceur soient traités tout de suite.
  env TP_INSIDE=1 TP_REAL_HOME="$HOME" HOME="$TP_DIR/home" \
    bash --rcfile "$SELF" -i <&0 &
  child=$!

  # Gardien : si le lanceur disparaît de force (kill -9...), il nettoie à sa place.
  (
    trap '' HUP INT
    exec >/dev/null 2>&1 </dev/null
    _tp_notty=1
    while kill -0 "$launcher_pid" 2>/dev/null; do sleep 1; done
    _tp_cleanup
  ) &
  wd=$!

  while kill -0 "$child" 2>/dev/null; do
    wait "$child" 2>/dev/null
  done

  _tp_cleanup
  echo
  echo "TP terminé. Rien n'a été conservé."
  exit 0

fi

# ---------------------------------------------------------------------
#  PARTIE 2 : le shell de TP (chargé comme --rcfile)
# ---------------------------------------------------------------------

set +H   # pas d'expansion d'historique (!) pendant le chargement du TP

# bashrc du bac à sable (c'est ici que l'élève met ses citations)
[[ -f "$HOME/.bashrc" ]] && source "$HOME/.bashrc"

# --- couleurs ---
if [[ -t 1 ]]; then
  B=$'\e[1m'; D=$'\e[2m'; R=$'\e[0m'
  RED=$'\e[31m'; GRN=$'\e[32m'; YEL=$'\e[33m'; MAG=$'\e[35m'
else
  B=; D=; R=; RED=; GRN=; YEL=; MAG=
fi

# --- état (uniquement en mémoire) ---
tp_step=1

# historique en mémoire seulement : jamais écrit sur le disque
# (pour savoir quelle commande vient d'être tapée)
unset HISTFILE
HISTSIZE=2000
HISTCONTROL=
set -o history
_tp_last_hn=$(HISTTIMEFORMAT= history 1 | awk '{print $1}')

# --- affichage ---
_tp_title() {
  case $1 in
    1) echo "Installer xeyes" ;;
    2) echo "Le terminal qui ne répond plus" ;;
    3) echo "Passer en arrière-plan" ;;
    4) echo "L'invasion" ;;
    5) echo "Tous les tuer" ;;
    6) echo "Une citation au démarrage" ;;
    7) echo "Le secret caché" ;;
    8) echo "Bonus : faire le ménage" ;;
  esac
}

_tp_show() {
  if (( tp_step > TP_TOTAL )); then _tp_final; return; fi
  echo
  echo "${B}${MAG}━━ Étape $tp_step/$TP_TOTAL : $(_tp_title "$tp_step") ━━${R}"
  echo
  case $tp_step in
    1)
      echo "Installe ${B}xeyes${R} avec ${B}apt${R}."
      echo "Le paquet qui le contient s'appelle ${B}x11-apps${R}."
      echo "${D}(Il te faudra sudo.)${R}"
      ;;
    2)
      echo "Tape ${B}xeyes${R} et regarde les yeux te suivre."
      echo
      echo "${RED}Oh non !${R} Ton terminal se concentre sur xeyes et ne répond plus."
      echo "Ouvre un ${B}deuxième terminal${R}, trouve le ${B}PID${R} de xeyes, et tue-le."
      echo
      echo "${D}Je vérifierai que xeyes a été tué (et pas fermé avec Ctrl+C).${R}"
      ;;
    3)
      echo "Le terminal était bloqué car xeyes tournait en ${B}avant-plan${R}."
      echo "On peut le lancer en ${B}arrière-plan${R} en ajoutant un ${B}&${R} à la fin."
      echo
      echo "Essaie, puis vérifie que ton terminal répond toujours."
      ;;
    4)
      echo "Pour lancer plusieurs xeyes d'un coup, on utilise une ${B}boucle${R}."
      echo "Je la lance pour toi :"
      echo
      echo "  ${B}for i in {1..5}; do xeyes & done${R}"
      echo
      echo "5 xeyes tournent maintenant. Appuie sur Entrée pour continuer."
      ;;
    5)
      echo "${RED}Il y a une invasion de xeyes !${R}"
      echo "Tue-les ${B}tous${R}, le plus efficacement possible."
      ;;
    6)
      echo "Fais en sorte que ta ${B}citation préférée${R} s'affiche à chaque"
      echo "ouverture de terminal."
      echo
      echo "${D}Ici, ton ~ est un bac à sable : modifier ~/.bashrc ne casse rien."
      echo "Pour tester, tape ${R}source ~/.bashrc${D}.${R}"
      ;;
    7)
      echo "Ajoute une ${B}2e citation, plus cachée${R} : elle ne s'affiche ${B}pas${R}"
      echo "au démarrage, seulement quand on tape la commande ${B}mon_secret${R}."
      echo
      echo "${D}Pour tester : ${R}source ~/.bashrc${D} puis ${R}mon_secret${D}.${R}"
      ;;
    8)
      echo "${B}Bonus${R} : désinstalle xeyes avec ${B}apt${R} (le paquet est ${B}x11-apps${R})."
      echo
      echo "Tu ne veux pas le faire ? Tape ${B}exit${R} pour sortir du TP."
      ;;
  esac
  echo
}

_tp_final() {
  echo
  echo "${B}${YEL}   ★ ★ ★  CERTIFICAT DE PHILOSOPHE LINUX  ★ ★ ★${R}"
  echo
  echo "   Tu sais installer, lancer, tuer, backgrounder, scripter"
  echo "   et personnaliser ton terminal. Et tu as une citation."
  echo
  echo "   ${D}Pour sortir du TP : exit${R}"
  echo
}

_tp_cheat() {
  echo
  echo "${YEL}Ctrl+C, c'est tricher ;)${R} Cette fois, trouve le PID et utilise ${B}kill${R}."
  echo
}

# --- actions déclenchées à l'entrée d'une étape ---
_tp_enter() {
  case $tp_step in
    4)
      { for i in {1..5}; do xeyes >/dev/null 2>&1 & done; } 2>/dev/null
      disown -a 2>/dev/null
      ;;
  esac
}

# --- validation ---
_tp_sandbox_run() {   # exécute une commande dans un nouveau shell qui charge le .bashrc du bac à sable
  timeout 5 env -i HOME="$HOME" PATH="$PATH" TERM="${TERM:-xterm}" \
    bash --norc --noprofile -c 'shopt -s expand_aliases; source "$HOME/.bashrc" 2>/dev/null; eval "$1"' _ "$1" \
    </dev/null 2>/dev/null
}

_tp_ok() {   # $1 = dernière commande (vide si rien de nouveau), $2 = son code retour
  local cmd=$1 rc=$2 re
  case $tp_step in
    1) command -v xeyes >/dev/null 2>&1 ;;
    2)
      re='^[[:space:]]*xeyes[[:space:]]*$'
      [[ $cmd =~ $re ]] || return 1
      case $rc in
        143|137|129) return 0 ;;
        130) _tp_cheat; return 1 ;;
        *) return 1 ;;
      esac
      ;;
    3)
      re='^[[:space:]]*xeyes[[:space:]]*&[[:space:]]*$'
      [[ $cmd =~ $re ]] && pgrep -u "$UID" -x xeyes >/dev/null 2>&1
      ;;
    4)
      # étape passive : validée au prompt suivant (quand l'élève appuie sur Entrée)
      return 0
      ;;
    5) ! pgrep -u "$UID" -x xeyes >/dev/null 2>&1 ;;
    6)
      local out
      out=$(_tp_sandbox_run ':')
      [[ -n "${out//[[:space:]]/}" ]]
      ;;
    7)
      local base full secret
      base=$(_tp_sandbox_run ':')
      [[ -n "$(_tp_sandbox_run 'type mon_secret >/dev/null 2>&1 && echo __OK__' | grep __OK__)" ]] || return 1
      full=$(_tp_sandbox_run 'mon_secret')
      # on retire de la sortie les lignes déjà affichées au démarrage
      secret=$(grep -vxF -f <(printf '%s\n' "$base") <<<"$full")
      [[ -n "${secret//[[:space:]]/}" ]]
      ;;
    8) ! command -v xeyes >/dev/null 2>&1 ;;
    *) return 1 ;;
  esac
}

_tp_success() {
  local msg
  case $tp_step in
    1) msg="xeyes est installé." ;;
    2) msg="Tué proprement. Le prompt est revenu !" ;;
    3) msg="Le terminal reste libre pendant que xeyes tourne." ;;
    4) msg="Invasion en cours..." ;;
    5) msg="Plus un seul œil à l'horizon." ;;
    6) msg="Belle citation !" ;;
    7) msg="Le secret est bien gardé." ;;
    8) msg="Propre. Tout est rangé." ;;
  esac
  echo
  echo "${B}${GRN}✔ Étape $tp_step réussie !${R} $msg"
  tp_step=$(( tp_step + 1 ))
  _tp_show
  _tp_enter
}

_tp_prompt() {
  local rc=$? line hn cmd
  (( tp_step > TP_TOTAL )) && return $rc
  line=$(HISTTIMEFORMAT= history 1)
  hn=$(awk '{print $1}' <<<"$line")
  cmd=$(sed -E 's/^[[:space:]]*[0-9]+\*?[[:space:]]+//' <<<"$line")
  if [[ "$hn" != "$_tp_last_hn" ]]; then
    _tp_last_hn=$hn
  else
    cmd=""
  fi
  hash -r
  if _tp_ok "$cmd" "$rc"; then _tp_success; fi
  return $rc
}

# --- la commande « tp » : réaffiche l'étape en cours ---
tp() { _tp_show; }

# --- prompt et démarrage ---
_tp_ps() { (( tp_step > TP_TOTAL )) && printf '★' || printf '%d/%d' "$tp_step" "$TP_TOTAL"; }
PS1='\[\e[1;35m\][TP $(_tp_ps)]\[\e[0m\] \[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '
PROMPT_COMMAND=_tp_prompt

clear 2>/dev/null
echo
echo "${B}   Bienvenue dans le TP « Jouer avec des yeux »${R}"
_tp_show

set -H   # on rend le comportement normal à l'élève
